package com.probiz.estore.core.security;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

import org.acegisecurity.Authentication;
import org.acegisecurity.ConfigAttribute;
import org.acegisecurity.ConfigAttributeDefinition;
import org.acegisecurity.GrantedAuthority;
import org.acegisecurity.context.SecurityContextHolder;
import org.acegisecurity.intercept.web.FilterSecurityInterceptor;
import org.acegisecurity.intercept.web.PathBasedFilterInvocationDefinitionMap;
import org.springframework.aop.MethodBeforeAdvice;
import org.springframework.context.support.ApplicationObjectSupport;

import com.probiz.estore.common.helper.ConfigUtil;
import com.probiz.estore.core.exception.AccessDeniedException;

public class AuthorizationInterceptor extends ApplicationObjectSupport implements MethodBeforeAdvice  {
	/**
	 * 是否开启对业务资源权限的保护,默认开启,资源权限的保护在这一层次(业务逻辑层)进行
	 */
	private boolean enableBusAuthz=true;
	public void before(Method method, Object[] args, Object target) throws Throwable {
		if(!isEnableBusAuthz())
			return;
		String methodName = method.getName();
//		String className = method.getDeclaringClass().getName();
//		System.out.println("----"+className+"-------"+target+"----"+methodName);
//		Type t = target.getClass().getGenericSuperclass();    
//        System.out.println(t);     
//        if (ParameterizedType.class.isAssignableFrom(t.getClass())) {  
//			System.out.print("----------->getActualTypeArguments:");     
//			for (Type t1:((ParameterizedType)t).getActualTypeArguments()) {     
//				System.out.print(t1 + ",");     
//			} 
//			System.out.println();     
//        }  

		methodName = target.getClass() + "." + methodName;
		//entityClass =(Class) ((ParameterizedType) getClass(){method.getDeclaringClass().getGenericSuperclass().getActualTypeArguments()[0];
		
		if (!SecurityContextHolder.getContext().getAuthentication().isAuthenticated()) {
			throw new AccessDeniedException("Not authenticated!");
		}
		ConfigAttributeDefinition cad = null;
		if(!ConfigUtil.getInstance().getIsStoreFront()){
			UrlRegExpBasedFilterInvocationDefinitionMap source = (UrlRegExpBasedFilterInvocationDefinitionMap) getApplicationContext().getBean("urlRegExpBasedFilterInvocationDefinitionMap");
			cad = source.lookupAttributes(methodName);
		}else{
			FilterSecurityInterceptor source = (FilterSecurityInterceptor) getApplicationContext().getBean("filterInvocationInterceptor");
			//spring-security.xml配置PATTERN_TYPE_APACHE_ANT时对应PathBasedFilterInvocationDefinitionMap
			PathBasedFilterInvocationDefinitionMap fi = (PathBasedFilterInvocationDefinitionMap)source.getObjectDefinitionSource();
			cad = fi.lookupAttributes(methodName);
		}
		final Collection<GrantedAuthority> granted = getPrincipalAuthorities();//获取当前用户所授予的角色实体类(Set<RoleEntity>)
		final Set<String> authzs = getAuthenticatedAuthorities(cad);//获取当前字串需要的角色名(Set<String>)
		
		//打印调试信息到控制台
		System.out.print("---> "+methodName+"--->"+authzs+"--->");
		for (Iterator<GrantedAuthority> i2 = granted.iterator(); i2.hasNext();) {
			GrantedAuthority au2 = i2.next();
			System.out.print(au2.getAuthority()+",");
		}
		System.out.println();
		
		//业务权限判断开始
		if(authzs==null||authzs.isEmpty())
			return;
		
		boolean authz=false;
		for(Iterator<String> i1 = authzs.iterator(); !authz&&i1.hasNext();){
			String au1=i1.next();
			for (Iterator<GrantedAuthority> i2 = granted.iterator(); i2.hasNext();) {
	            GrantedAuthority au2 = i2.next();
	            if (null != au2.getAuthority()&&au1.equals(au2.getAuthority())) {
	            	authz=true;
	            	return;
	            }
			}
		}
		
		if(!authz)
			throw new AccessDeniedException("未授予此业务权限,拒绝访问!");
	}
	
	private Set<String> getAuthenticatedAuthorities(ConfigAttributeDefinition cad){
		if(cad==null)
			return null;
		Set<String> target = new HashSet<String>();
        Iterator<ConfigAttribute> it = cad.getConfigAttributes();
        while (it.hasNext()) {
            ConfigAttribute ca = (ConfigAttribute) it.next();                
            // get the role name from configAttribute
            target.add(ca.getAttribute());
        }
        return target;
	}
	
	private Collection<GrantedAuthority> getPrincipalAuthorities() {
        Authentication currentUser = SecurityContextHolder.getContext().getAuthentication();

        if (null == currentUser) {
            return Collections.EMPTY_LIST;
        }

        if ((null == currentUser.getAuthorities()) || (currentUser.getAuthorities().length < 1)) {
            return Collections.EMPTY_LIST;
        }

        Collection<GrantedAuthority> granted = Arrays.asList(currentUser.getAuthorities());

        return granted;
    }

	public boolean isEnableBusAuthz() {
		return enableBusAuthz;
	}

	public void setEnableBusAuthz(boolean enableBusAuthz) {
		this.enableBusAuthz = enableBusAuthz;
	}

}
